/*
 *       This file is part of VFC.
 *
 *        VFC is free software: you can redistribute it and/or modify
 *        it under the terms of the GNU General Public License as published by
 *        the Free Software Foundation, either version 3 of the License, or
 *        (at your option) any later version.
 *
 *        VFC is distributed in the hope that it will be useful,
 *        but WITHOUT ANY WARRANTY; without even the implied warranty of
 *        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *        GNU General Public License for more details.
 *
 *        You should have received a copy of the GNU General Public License
 *        along with VFC.  If not, see <http://www.gnu.org/licenses/>.
 */


using System;
using System.Collections.Generic;
using System.Text;

namespace VFC.Nes.Cpu.Opcode
{
    class Implied
    {
        private static int MSB = 0, LSB = 0, Addr = 0;

        public static void TAX()
        {
            Cpu.Register.X = Cpu.Register.A;
            Flags.CheckForZeroFlag(Cpu.Register.X);
            Flags.CheckForNegativeFlag(Cpu.Register.X);
            Cpu.Register.PC += Cpu.Core.Size[Cpu.Core._Opcode_];
        }

        public static void TAY()
        {
            Cpu.Register.Y = Cpu.Register.A;
            Flags.CheckForZeroFlag(Cpu.Register.Y);
            Flags.CheckForNegativeFlag(Cpu.Register.Y);
            Cpu.Register.PC += Cpu.Core.Size[Cpu.Core._Opcode_];
        }

        public static void TXA()
        {
            Cpu.Register.A = Cpu.Register.X;
            Flags.CheckForZeroFlag(Cpu.Register.A);
            Flags.CheckForNegativeFlag(Cpu.Register.A);
            Cpu.Register.PC += Cpu.Core.Size[Cpu.Core._Opcode_];
        }

        public static void TYA()
        {
            Cpu.Register.A = Cpu.Register.Y;
            Flags.CheckForZeroFlag(Cpu.Register.A);
            Flags.CheckForNegativeFlag(Cpu.Register.A);
            Cpu.Register.PC += Cpu.Core.Size[Cpu.Core._Opcode_];
        }

        public static void TSX()
        {
            Cpu.Register.X = Cpu.Register.SP;
            Flags.CheckForZeroFlag(Cpu.Register.X);
            Flags.CheckForNegativeFlag(Cpu.Register.X);
            Cpu.Register.PC += Cpu.Core.Size[Cpu.Core._Opcode_];
        }

        public static void TXS()
        {
            Cpu.Register.SP = Cpu.Register.X;
            Cpu.Register.PC += Cpu.Core.Size[Cpu.Core._Opcode_];
        }

        public static void PHA()
        {
            Cpu.Stack.Push(Cpu.Register.A);
            Cpu.Register.PC += Cpu.Core.Size[Cpu.Core._Opcode_];
        }

        public static void PHP()
        {
            Cpu.Stack.Push(Cpu.Register.SR | 0x30);     //Set the bit 4 and 5 during push...
            Cpu.Register.PC += Cpu.Core.Size[Cpu.Core._Opcode_];
        }

        public static void PLA()
        {
            Cpu.Register.A = Cpu.Stack.Pull();
            Flags.CheckForZeroFlag(Cpu.Register.A);
            Flags.CheckForNegativeFlag(Cpu.Register.A);
            Cpu.Register.PC += Cpu.Core.Size[Cpu.Core._Opcode_];
        }

        public static void PLP()
        {
            Cpu.Register.SR = (Cpu.Stack.Pull() & 0xef) | 0x20;    //Clear bit 4 and set bit 5....
            Cpu.Register.PC += Cpu.Core.Size[Cpu.Core._Opcode_];
        }

        public static void INX()
        {
            Cpu.Register.X = (Cpu.Register.X + 1) & 0xff;
            Flags.CheckForZeroFlag(Cpu.Register.X);
            Flags.CheckForNegativeFlag(Cpu.Register.X);
            Cpu.Register.PC += Cpu.Core.Size[Cpu.Core._Opcode_];
        }

        public static void INY()
        {
            Cpu.Register.Y = (Cpu.Register.Y + 1) & 0xff;
            Flags.CheckForZeroFlag(Cpu.Register.Y);
            Flags.CheckForNegativeFlag(Cpu.Register.Y);
            Cpu.Register.PC += Cpu.Core.Size[Cpu.Core._Opcode_];
        }

        public static void DEX()
        {
            Cpu.Register.X = (Cpu.Register.X - 1) & 0xff;
            Flags.CheckForZeroFlag(Cpu.Register.X);
            Flags.CheckForNegativeFlag(Cpu.Register.X);
            Cpu.Register.PC += Cpu.Core.Size[Cpu.Core._Opcode_];
        }

        public static void DEY()
        {
            Cpu.Register.Y = (Cpu.Register.Y - 1) & 0xff;
            Flags.CheckForZeroFlag(Cpu.Register.Y);
            Flags.CheckForNegativeFlag(Cpu.Register.Y);
            Cpu.Register.PC += Cpu.Core.Size[Cpu.Core._Opcode_];
        }

        public static void RTS()
        {
            LSB = Cpu.Stack.Pull();
            MSB = Cpu.Stack.Pull();
            Addr = (MSB << 8) | LSB;
            Cpu.Register.PC = Addr;
            Cpu.Register.PC++;
            Cpu.Register.PC &= 0xffff;
        }

        public static void CLC()
        {
            Cpu.Register.ClearCarryFlag();
            Cpu.Register.PC += Cpu.Core.Size[Cpu.Core._Opcode_];
        }

        public static void CLD()
        {
            Cpu.Register.ClearDecimalFlag();
            Cpu.Register.PC += Cpu.Core.Size[Cpu.Core._Opcode_];
        }

        public static void CLI()
        {
            Cpu.Register.ClearInterruptFlag();
            Cpu.Register.PC += Cpu.Core.Size[Cpu.Core._Opcode_];
        }

        public static void CLV()
        {
            Cpu.Register.ClearOverflowFlag();
            Cpu.Register.PC += Cpu.Core.Size[Cpu.Core._Opcode_];
        }

        public static void SEC()
        {
            Cpu.Register.SetCarryFlag();
            Cpu.Register.PC += Cpu.Core.Size[Cpu.Core._Opcode_];
        }

        public static void SED()
        {
            Cpu.Register.SetDecimalFlag();
            Cpu.Register.PC += Cpu.Core.Size[Cpu.Core._Opcode_];
        }

        public static void SEI()
        {
            Cpu.Register.SetInterruptFlag();
            Cpu.Register.PC += Cpu.Core.Size[Cpu.Core._Opcode_];
        }

        public static void BRK()
        {
            Cpu.Stack.Push((Cpu.Register.PC + 2) >> 8);
            Cpu.Stack.Push((Cpu.Register.PC + 2) & 0xff);
            Cpu.Stack.Push(Cpu.Register.SR | 0x30);         //Set bit 4 and bit 5 during push...
            Cpu.Register.PC = Cpu.Memory.GetIrqVector();
        }

        public static void NOP()
        {
            Cpu.Register.PC++;
        }

        public static void RTI()
        {
            Cpu.Register.SR = (Cpu.Stack.Pull() & 0xef) | 0x20;
            LSB = Cpu.Stack.Pull();
            MSB = Cpu.Stack.Pull();
            Cpu.Register.PC = (MSB << 8) | LSB;
        }
    }
}
